/*
			       ___ _      _   ___ _  _    ___  _  _ 
			      | __| |    /_\ / __| || |  / _ \| \| |
			      | _|| |__ / _ \\__ \ __ | | (_) | .` |
			      |_| |____/_/ \_\___/_||_|  \___/|_|\_|
			                                            
			  _____ _  _   _ _____   ___ ___ _____ ___ _  _ 
			 |_   _| || | /_\_   _| | _ )_ _|_   _/ __| || |
			   | | | __ |/ _ \| |   | _ \| |  | || (__| __ |
			   |_| |_||_/_/ \_\_|   |___/___| |_| \___|_||_|
			        F L A S H  O N  T H A T  B I T C H
			        
		+--------------------------------------------------------+
		|	This file is delivered as is. Any modifications to   |
		|   this class and/or sub classes may cause errors and   |
		|   can cause you compilations to fail. FOTB takes no	 |
		|   responsibility for any complications caused by the	 |
		|   following code or any modified versions of it.		 |
		+--------------------------------------------------------+

*/
package com.flashonthatbitch.filesystem {

/*
		 ___ __  __ ___  ___  ___ _____ 
		|_ _|  \/  | _ \/ _ \| _ \_   _|
		 | || |\/| |  _/ (_) |   / | |  
		|___|_|  |_|_|  \___/|_|_\ |_|  
		I M P O R T
*/
	
	import flash.filesystem.File;
	import flash.filesystem.FileMode;
	import flash.filesystem.FileStream;
	import flash.utils.ByteArray;

	public class FileObject extends File implements IFile {
		
		private var $filestream		:ExtendedFileStream		= null;
		
/*
		  ___ ___  _  _ ___ _____ ___ _   _  ___ _____ ___  ___ 
		 / __/ _ \| \| / __|_   _| _ \ | | |/ __|_   _/ _ \| _ \
		| (_| (_) | .` \__ \ | | |   / |_| | (__  | || (_) |   /
		 \___\___/|_|\_|___/ |_| |_|_\\___/ \___| |_| \___/|_|_\
		C O N S T R U C T O R
*/
		
		/**
		 * Creates a FileObject.
		 *  
		 * @param path		path to the file.
		 * 
		 */
		public function FileObject(path:String=null) {
			
			super(path);
			
			$filestream = new ExtendedFileStream();
			
			if(path && isDirectory)
				throw getError("FileObject '" + nativePath +"' is a Folder. Use the Folder class for directories.");
		}

/*		
		 ___ _   _ ___ _    ___ ___ 
		| _ \ | | | _ ) |  |_ _/ __|
		|  _/ |_| | _ \ |__ | | (__ 
		|_|  \___/|___/____|___\___|
		P U B L I C
*/
		
		/**
		 * Writes the specified object to the file.
		 *  
		 * @param obj		Object to write
		 * @param type		Type of object write (default: UTF as String)
		 * @param mode		Stream mode. Available options are WRITE, UPDATE or APPEND.
		 * 
		 */
		public function write(obj:*, type:String=FileWriteMode.WRITE_UTF, mode:String=FileMode.WRITE):void {
			if(exists){
				$filestream.open(this,mode);
				try {
					$filestream[type](obj);
				}catch(e:*) {
					$filestream.close();
					throw getError("Unable to write '"+obj+"' to '" + nativePath + "' through '" + type + "'. Make sure that the object matches the type!");
				}
				$filestream.close();
			}else
				throw getError("Unable to write '"+obj+"' to '" + nativePath + "' through '" + type + "'. The file does not exist!");
		}
		
		/**
		 * Reads the file by the specified type.
		 *  
		 * @param type		Type of the return. (default: UTF as String)
		 * @return 			File content
		 * 
		 */
		public function read(type:String=FileReadMode.READ_UTF):* {
			if(exists){
				var ret:*;
				$filestream.open(this,FileMode.READ);
				try{
					switch(type){
						case FileReadMode.READ_UTF:
							ret = $filestream.readUTFBytes($filestream.bytesAvailable);
							break;
						case FileReadMode.READ_BYTES :
							ret = new ByteArray();
							$filestream.readBytes(ret, 0, $filestream.bytesAvailable);
							break;
						default:
							ret = $filestream[type]();
					}
				}catch(e:*) {
					$filestream.close();
					throw getError("Unable to read through '"+type+"' from '" + nativePath + "'.");
				}
				$filestream.close();
				return ret;
			}else
				throw getError("Unable to read through '"+type+"' from '" + nativePath + "'. The file does not exist!");
		}

/*
		  ___ ___ _____   ___ ___ _____ 
		 / __| __|_   _| / __| __|_   _|
		| (_ | _|  | |   \__ \ _|  | |  
		 \___|___| |_|   |___/___| |_|  
		G E T  S E T
*/
		
		/**
		 * Traces the current state of the file.
		 * 
		 */	
		public function expose():void {
			trace(toString());
		}
		
		/**
		 * Parent folder.
		 *  
		 * @return		The parent folder as a Folder object 
		 * 
		 */
		public function get parentFolder():Folder {
			return new Folder(this.parent.nativePath);
		}
		
		/**
		 * Locks the file to prevent changes from other sources.
		 *  
		 * @param value		Lock or unlock
		 * 
		 */
		public function set lock(value:Boolean):void {
			if(value){
				if($filestream.isOpen)	$filestream.close();
				$filestream.open(this,FileMode.READ);
			}else if($filestream.isOpen)
				$filestream.close();
		}
		
		/**
		 * Returns true if the file is open.
		 *  
		 * @return 	state of the file
		 * 
		 */
		public function get isOpen():Boolean {
			return $filestream.isOpen;
		}
		
		/**
		 * [internal-use]
		 * Returns a pre-defined error with the specified message.
		 *  
		 * @param message		Message
		 * @return 				FileObjectError object
		 * 
		 */
		private function getError(message:String):Error {
			var err:Error = new Error(message);
			err.name = "FileObjectError";
			return err;
		}
		
	}
	
}

import flash.filesystem.File;
import flash.filesystem.FileStream;

internal class ExtendedFileStream extends FileStream {
	
	private var $isOpen:Boolean = false;
	
	public function ExtendedFileStream(){
		super();
	}
		
	override public function open(file:File, fileMode:String):void {
		super.open(file,fileMode);
		$isOpen = true;
	}
	
	override public function close():void {
		super.close();
		$isOpen = false;
	}
	
	public function get isOpen():Boolean {
		return $isOpen;
	}
	
} 